package cloud.tianai.captcha.spring.plugins;

import cloud.tianai.captcha.common.constant.CommonConstant;
import cloud.tianai.captcha.common.util.CollectionUtils;
import cloud.tianai.captcha.resource.ResourceStore;
import cloud.tianai.captcha.resource.common.model.dto.Resource;
import cloud.tianai.captcha.resource.common.model.dto.ResourceMap;
import com.google.gson.Gson;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @Author: 天爱有情
 * @date 2023/8/23 10:52
 * @Description 基于redis的store
 */
@RequiredArgsConstructor
public class RedisResourceStore implements ResourceStore {


    private final StringRedisTemplate redisTemplate;

    @Getter
    @Setter
    private String resourcePrefix = "captcha:config:resource:";
    @Getter
    @Setter
    private String templatePrefix = "captcha:config:template:";
    private Gson gson = new Gson();

    public String joinResourceKey(String type, String tag) {
        if (tag == null) {
            tag = CommonConstant.DEFAULT_TAG;
        }
        type = type.toUpperCase();
        return resourcePrefix + tag + ":" + type;
    }

    public String joinTemplateKey(String type, String tag) {
        if (tag == null) {
            tag = CommonConstant.DEFAULT_TAG;
        }
        type = type.toUpperCase();
        return templatePrefix + tag + ":" + type;
    }

    public List<Resource> getResources(String type, String tag) {
        String key = joinResourceKey(type, tag);
        Long size = redisTemplate.opsForList().size(key);
        if (size == null || size < 1) {
            return Collections.emptyList();
        }
        List<String> range = redisTemplate.opsForList().range(key, 0, size);
        List<Resource> result = new ArrayList<>(range.size());
        for (String json : range) {
            result.add(gson.fromJson(json, Resource.class));
        }

        return result;
    }

    public List<ResourceMap> getTemplates(String type, String tag) {
        String key = joinTemplateKey(type, tag);
        Long size = redisTemplate.opsForList().size(key);
        if (size == null || size < 1) {
            return Collections.emptyList();
        }
        List<String> range = redisTemplate.opsForList().range(key, 0, size);
        List<ResourceMap> result = new ArrayList<>(range.size());
        for (String json : range) {
            result.add(gson.fromJson(json, ResourceMap.class));
        }
        return result;
    }


    public void setResources(String type, String tag, List<Resource> resources) {
        String key = joinResourceKey(type, tag);
        Long size = redisTemplate.opsForList().size(key);
        if (size != null && size > 0) {
            redisTemplate.delete(key);
        }
        for (Resource resource : resources) {
            addResource(type, resource);
        }
    }

    public void setTemplates(String type, String tag, List<ResourceMap> templates) {
        String key = joinTemplateKey(type, tag);
        Long size = redisTemplate.opsForList().size(key);
        if (size != null && size > 0) {
            redisTemplate.delete(key);
        }
        for (ResourceMap template : templates) {
            addTemplate(type, template);
        }
    }

    @Override
    public void addResource(String type, Resource resource) {
        // 添加tag标签字典
        redisTemplate.opsForList().rightPush(joinResourceKey(type, resource.getTag()), gson.toJson(resource));
    }

    @Override
    public void addTemplate(String type, ResourceMap template) {
        // 添加tag标签字典
        redisTemplate.opsForList().rightPush(joinTemplateKey(type, template.getTag()), gson.toJson(template));
    }

    @Override
    public Resource randomGetResourceByTypeAndTag(String type, String tag) {
        String key = joinResourceKey(type, tag);
        Long size = redisTemplate.opsForList().size(key);
        if (size == null || size < 1) {
            throw new IllegalStateException("随机获取资源错误，store中资源为空, type:" + type);
        }
        long index = 0L;
        if (size > 1) {
            index = ThreadLocalRandom.current().nextLong(size);
        }
        String resourceJson = redisTemplate.opsForList().index(key, index);
        return gson.fromJson(resourceJson, Resource.class);
    }

    @Override
    public ResourceMap randomGetTemplateByTypeAndTag(String type, String tag) {
        String key = joinTemplateKey(type, tag);
        Long size = redisTemplate.opsForList().size(key);
        if (size == null || size < 1) {
            throw new IllegalStateException("随机获取模板错误，store中模板为空, type:" + type);
        }

        long index = 0L;
        if (size > 1) {
            index = ThreadLocalRandom.current().nextLong(size);
        }
        String resourceJson = redisTemplate.opsForList().index(key, index);
        return gson.fromJson(resourceJson, ResourceMap.class);
    }

    @Override
    public void clearAllTemplates() {
        Set<String> keys = redisTemplate.keys(templatePrefix + "*");
        if (!CollectionUtils.isEmpty(keys)) {
            redisTemplate.delete(keys);
        }
    }

    @Override
    public void clearAllResources() {
        Set<String> keys = redisTemplate.keys(resourcePrefix + "*");
        if (!CollectionUtils.isEmpty(keys)) {
            redisTemplate.delete(keys);
        }
    }

}
